package de.schmidke.palmreader;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

public class AddressEntry extends Readable {
	private final Logger logger = Logger
			.getLogger(AddressEntry.class.getName());

	public static String t(String s) {
		if (s == null)
			return null;
		return s.trim();
	}

	public static boolean e(String s) {
		return (s == null || s.isEmpty());
	}

	public static class Address {
		private String address;
		private String city;
		private String state;
		private String zip;
		private String country;
		private int type;

		public String getAddress() {
			return t(address);
		}

		public String getCity() {
			return t(city);
		}

		public String getState() {
			return t(state);
		}

		public String getZip() {
			return t(zip);
		}

		public String getCountry() {
			return t(country);
		}

		public int getType() {
			return type;
		}

		public boolean isEmpty() {
			return e(getAddress()) && e(getCity()) && e(getState())
					&& e(getZip()) && e(getCountry());
		}
	}

	private enum Field {
		PALM_ID, FIELD_1, STATUS, FIELD_3, FIELD_4, CATEGORY, FIELD_6, FIELD_7, FIELD_8, FIELD_9, PROFILE_IMAGE, FIELD_11, FIELD_12, FIRST, NAME, TITLE, COMPANY, FIELD_17, NOTE, PHONE0, PHONE1, PHONE2, PHONE3, PHONE4, PHONE5, PHONE6, PHONE0_LABEL_ID, PHONE1_LABEL_ID, PHONE2_LABEL_ID, PHONE3_LABEL_ID, PHONE4_LABEL_ID, PHONE5_LABEL_ID, PHONE6_LABEL_ID, CUSTOM1, CUSTOM2, CUSTOM3, CUSTOM4, CUSTOM5, CUSTOM6, CUSTOM7, CUSTOM8, CUSTOM9, ADDRESS0_TYPE, ADDRESS0_ADDRESS, ADDRESS0_CITY, ADDRESS0_STATE, ADDRESS0_ZIP, ADDRESS0_COUNTRY, ADDRESS1_TYPE, ADDRESS1_ADDRESS, ADDRESS1_CITY, ADDRESS1_STATE, ADDRESS1_ZIP, ADDRESS1_COUNTRY, ADDRESS2_TYPE, ADDRESS2_ADDRESS, ADDRESS2_CITY, ADDRESS2_STATE, ADDRESS2_ZIP, ADDRESS2_COUNTRY
	}

	private final AddressDat parent;
	private int recordId;
	private int statusField;
	private int position;
	private String name;
	private String first;
	private String title;
	private String company;
	private PalmPhoneNumber[] phone;
	private Address address0 = new Address();
	private Address address1 = new Address();
	private Address address2 = new Address();
	private String note;
	private boolean privat;
	private int category;
	private String custom1;
	private String custom2;
	private String custom3;
	private String custom4;

	public AddressEntry(AddressDat parent) {
		this.parent = parent;
	}

	private void loadNewFormat() throws IOException {
		phone = new PalmPhoneNumber[7];
		for (int i = 0; i < parent.getFieldsPerRow(); i++) {
			Object object = readProperty();

			if (i >= Field.values().length) {
				continue;
			}
			Field field = Field.values()[i];

			if (object instanceof String) {
				String value = (String) object;
				logger.finest("field[" + field + "] = \"" + value + "\"");
				switch (field) {
				case FIRST:
					first = value;
					break;
				case NAME:
					name = value;
					break;
				case TITLE:
					title = value;
					break;
				case COMPANY:
					company = value;
					break;
				case NOTE:
					note = value;
					break;
				case PHONE0:
					phone[0] = new PalmPhoneNumber(value);
					break;
				case PHONE1:
					phone[1] = new PalmPhoneNumber(value);
					break;
				case PHONE2:
					phone[2] = new PalmPhoneNumber(value);
					break;
				case PHONE3:
					phone[3] = new PalmPhoneNumber(value);
					break;
				case PHONE4:
					phone[4] = new PalmPhoneNumber(value);
					break;
				case PHONE5:
					phone[5] = new PalmPhoneNumber(value);
					break;
				case PHONE6:
					phone[6] = new PalmPhoneNumber(value);
					break;
				case ADDRESS0_ADDRESS:
					address0.address = value;
					break;
				case ADDRESS0_CITY:
					address0.city = value;
					break;
				case ADDRESS0_STATE:
					address0.state = value;
					break;
				case ADDRESS0_ZIP:
					address0.zip = value;
					break;
				case ADDRESS0_COUNTRY:
					address0.country = value;
					break;
				case ADDRESS1_ADDRESS:
					address1.address = value;
					break;
				case ADDRESS1_CITY:
					address1.city = value;
					break;
				case ADDRESS1_STATE:
					address1.state = value;
					break;
				case ADDRESS1_ZIP:
					address1.zip = value;
					break;
				case ADDRESS1_COUNTRY:
					address1.country = value;
					break;
				case ADDRESS2_ADDRESS:
					address2.address = value;
					break;
				case ADDRESS2_CITY:
					address2.city = value;
					break;
				case ADDRESS2_STATE:
					address2.state = value;
					break;
				case ADDRESS2_ZIP:
					address2.zip = value;
					break;
				case ADDRESS2_COUNTRY:
					address2.country = value;
					break;
				default:
					break;
				}
			} else if (object instanceof Integer) {
				int value = (Integer) object;
				logger.finer("field[" + field + "] = " + value);
				switch (field) {
				case PALM_ID:
					recordId = value;
					break;
				case STATUS:
					statusField = value;
					break;
				case CATEGORY:
					category = value;
					break;
				case PROFILE_IMAGE:
					if (value != 0) {
						throw new UnsupportedOperationException(
								"Cannot import files with profile images.");
					}
					break;
				case PHONE0_LABEL_ID:
					if (phone[0] != null) {
						phone[0].setLabelId(value);
					}
					break;
				case PHONE1_LABEL_ID:
					if (phone[1] != null) {
						phone[1].setLabelId(value);
					}
					break;
				case PHONE2_LABEL_ID:
					if (phone[2] != null) {
						phone[2].setLabelId(value);
					}
					break;
				case PHONE3_LABEL_ID:
					if (phone[3] != null) {
						phone[3].setLabelId(value);
					}
					break;
				case PHONE4_LABEL_ID:
					if (phone[4] != null) {
						phone[4].setLabelId(value);
					}
					break;
				case PHONE5_LABEL_ID:
					if (phone[5] != null) {
						phone[5].setLabelId(value);
					}
					break;
				case PHONE6_LABEL_ID:
					if (phone[6] != null) {
						phone[6].setLabelId(value);
					}
					break;
				case ADDRESS0_TYPE:
					address0.type = value;
					break; // 1=Home 0=work
				case ADDRESS1_TYPE:
					address1.type = value;
					break; // 1=Home 0=work
				case ADDRESS2_TYPE:
					address2.type = value;
					break; // 1=Home 0=work
				default:
					break;
				}
			} else if (object instanceof Blob) {
				Blob blob = (Blob) object;
				logger.finer("field[" + field + "] = " + blob);
				if (blob.hasData()) {
					throw new UnsupportedOperationException(
							"Found binary data for field " + field);
				}
			}
		}
	}

	@Override
	protected void load() throws IOException {
		if (parent.isNewFileFormat()) {
			loadNewFormat();
			return;
		}
		recordId = readTypedInt();
		statusField = readTypedInt();
		position = readTypedInt();
		name = readTypedString();
		first = readTypedString();
		title = readTypedString();
		company = readTypedString();
		phone = new PalmPhoneNumber[5];
		for (int i = 0; i < 5; i++) {
			phone[i] = new PalmPhoneNumber();
			phone[i].load(is);
		}
		address0.address = readTypedString();
		address0.city = readTypedString();
		address0.state = readTypedString();
		address0.zip = readTypedString();
		address0.country = readTypedString();
		note = readTypedString();
		privat = readTypedBool();
		category = readTypedInt();
		custom1 = readTypedString();
		custom2 = readTypedString();
		custom3 = readTypedString();
		custom4 = readTypedString();
		int displayPhone = readTypedInt();
		phone[displayPhone - 1].setDefault(true);
	}

	public int getRecordId() {
		return recordId;
	}

	public int getStatusField() {
		return statusField;
	}

	public int getPosition() {
		return position;
	}

	public String getName() {
		return name;
	}

	public String getFirst() {
		return first;
	}

	public String getTitle() {
		return title;
	}

	public String getCompany() {
		return company;
	}

	public PalmPhoneNumber[] getPhone() {
		return phone;
	}

	public List<Address> getAddresses() {
		List<Address> addresses = new ArrayList<Address>();

		if (!address0.isEmpty()) {
			addresses.add(address0);
		}
		if (!address1.isEmpty()) {
			addresses.add(address1);
		}
		if (!address2.isEmpty()) {
			addresses.add(address2);
		}

		return addresses;
	}

	public String getNote() {
		return note;
	}

	public boolean isPrivat() {
		return privat;
	}

	public CategoryEntry getCategory() {
		return parent.getCat(category);
	}

	public String getCustom1() {
		return custom1;
	}

	public String getCustom2() {
		return custom2;
	}

	public String getCustom3() {
		return custom3;
	}

	public String getCustom4() {
		return custom4;
	}

	private void ap(StringBuilder sb, String was) {
		if (was == null)
			return;
		if (was.length() == 0)
			return;
		if (sb.length() > 0)
			sb.append(' ');
		sb.append(was);
	}

	public String getFullName() {
		StringBuilder r = new StringBuilder();
		ap(r, getTitle());
		ap(r, getFirst());
		ap(r, getName());
		ap(r, getCompany());
		return r.toString();
	}

	private String getGarminString(String sg, String neu) {
		if (sg != null)
			return sg;
		if (neu == null)
			return null;
		if (neu.startsWith("GARMIN "))
			return neu;
		return null;
	}

	public String getGarminString() {
		return getGarminString(getGarminString(getGarminString(getGarminString(
				null, getCustom4()), getCustom3()), getCustom2()), getCustom1());
	}

	public Waypoint getWaypoint() {
		String gs = getGarminString();
		if (gs != null) {
			return new Waypoint(gs);
		}
		return null;
	}

	public String getIdstring() {
		return "" + getRecordId();
	}
}
